package com.jishuo.nontax.bfc.service;

import com.jishuo.base.config.NonTaxConfig;
import com.jishuo.base.service.SequenceService;
import com.jishuo.base.util.GTimeUtil;
import com.jishuo.base.util.UniqId;
import com.jishuo.nontax.api.socket.SocketClientCore;
import com.jishuo.nontax.bean.message.HBFSDTO;
import com.jishuo.nontax.bean.message.SetBankPayFisc;
import com.jishuo.nontax.bean.message.efisc.*;
import com.jishuo.nontax.bean.vo.BankBalanceVO;
import com.jishuo.nontax.bean.vo.BankVO;
import com.jishuo.nontax.bean.vo.WaitaffirmVO;
import com.jishuo.nontax.bfc.ca.JDCA;
import com.jishuo.nontax.bfc.dao.BankMapper;
import com.jishuo.nontax.bfc.dao.EpayFiscMapper;
import com.jishuo.nontax.bfc.pzk.PzkService;
import com.jishuo.nontax.bfc.tlq.CertAndQueue;
import com.jishuo.nontax.bfc.tlq.MessageService;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.StringReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author hlp
 * @date 2023/11/7 13:54
 * @Description: 电子缴库
 */
@Service
public class EpayFiscService {
    private static Logger logger = LoggerFactory.getLogger(EpayFiscService.class);

    @Resource
    private NonTaxConfig nonTaxConfig;
    @Resource
    private EpayFiscMapper epayFiscMapper;
    @Resource
    private ParameterService parameterService;
    @Resource
    private SequenceService sequenceService;
    @Resource
    private MessageService messageService;
    @Resource
    private BankMapper bankMapper;
    @Resource
    private WaitaffirmPayInfoService waitaffirmPayInfoService;
    @Resource
    private WaitaffirmService waitaffirmService;
    @Resource
    private BankBalanceService bankBalanceService;


    public List<EpayFiscVO> findEpayFisc(String billNum, String payBankDt, String accountCode) {
        return this.epayFiscMapper.listFisc(billNum, payBankDt, accountCode);
    }

    /**
     * 添加扣款、对账
     * @param vo
     * @return
     */
    public int addFiscUnited(EpayFiscVO vo, String chkState) {
        if (vo.getAccountCode() == null || vo.getAccountCode().length() == 0) return -11;
        // 根据账户，获得bankid
        BankVO bank = this.bankMapper.findBankVO(vo.getAccountCode());
        if (bank == null) return 1; // 不存在的账户，直接跳过
        if (vo.getBillNum() == null || vo.getBillNum().length() == 0) return -11;
        if (vo.getTraNo() == null || vo.getTraNo().length() == 0) return -11;
        if (vo.getPayBankDt() == null || vo.getPayBankDt().length() != 19) return -11;
        if (vo.getBankAffirm() == null || vo.getBankAffirm().length() == 0) return -11;
        if (vo.getMoney().compareTo(BigDecimal.ZERO) <= 0) return -11;
        if (vo.getBankStation() == null || vo.getBankStation().length() == 0) vo.setBankStation("0000");

        int state = 2; // 默认对账成功。对于未传递这个参数的也按成功处理。
        if ("1".equals(chkState)) state = 1;
        if ("3".equals(chkState)) state = 3;
        if (state == 2) {
            // 对账成功，或未传state参数的也按成功处理
            if (vo.getChkAcctOrd() == null || vo.getChkAcctOrd().length() == 0) return -11;
            if (vo.getCheckDate() == null || vo.getCheckDate().length() != 10) return -11;
        }
        vo.setCantonid(bank.getCantonid().intValue());
        vo.setBankid(bank.getBankid().intValue());
        vo.setState(1);
        int n = this.addFiscInster(vo);
        if (n > 0) {
            if (state == 2) {
                vo.setState(2);
                n = this.epayFiscMapper.setCheck(vo);
            } else if (state == 3) {
                vo.setState(3);
                n = this.epayFiscMapper.setCheckFail(vo);
            }
        }
        return n;
    }

    public int addFiscInster(EpayFiscVO vo){
        if(epayFiscMapper.getPayFiscCount(vo.getBillNum())>0){
           return epayFiscMapper.updatePayFisc(vo);
        }else{
           return epayFiscMapper.insertPayFisc(vo);
        }
    }

    /**
     * 添加扣款
     * @param billNum 票号
     * @param traNo tips流水
     * @param accountCode 账户
     * @param payBankDt 交易日期
     * @param bankAffirm 交易流水
     * @param bankStation 网点
     * @param money 金额
     * @return 1-成功；0-入库失败；-11-参数错误
     */
    public int addFisc(String billNum, String traNo, String accountCode, String payBankDt, String bankAffirm, String bankStation, String money) {
        if (accountCode == null || accountCode.trim().length() == 0) return -11;
        // 根据账户，获得bankid
        BankVO bank = this.bankMapper.findBankVO(accountCode);
        if (bank == null) return 1; // 不存在的账户，直接跳过
        if (billNum == null || billNum.trim().length() == 0) return -11;
        if (traNo == null || traNo.trim().length() == 0) return -11;
        if (payBankDt == null || payBankDt.trim().length() != 19) return -11;
        if (bankAffirm == null || bankAffirm.trim().length() == 0) return -11;
        if (money == null || money.trim().length() == 0) return -11;
        BigDecimal amt = new BigDecimal(money);
        if (amt.compareTo(BigDecimal.ZERO) <= 0) return -11;
        if (bankStation == null || bankStation.trim().length() == 0) bankStation = "0000";

        EpayFiscVO vo = new EpayFiscVO();
        vo.setBillNum(billNum.trim());
        vo.setTraNo(traNo.trim());
        vo.setCantonid(bank.getCantonid().intValue());
        vo.setBankid(bank.getBankid().intValue());
        vo.setAccountName(bank.getAccountname());
        vo.setAccountCode(accountCode.trim());
        vo.setPayBankDt(payBankDt.trim());
        vo.setBankAffirm(bankAffirm.trim());
        vo.setBankStation(bankStation.trim());
        vo.setMoney(amt);
        vo.setState(1);

        return this.addFiscInster(vo);
    }

    /**
     * 保存对账流水
     * @param billNum 票号
     * @param chkAcctOrd 对账批次
     * @param checkDate 对账日期
     * @return 1-成功；0-入库失败；-11-参数错误
     */
    public int setCheck(String billNum, String chkAcctOrd, String checkDate, String chkState) {
        if (billNum == null || billNum.trim().length() == 0) return -11;

        EpayFiscVO vo = new EpayFiscVO();
        vo.setBillNum(billNum.trim());
        if ("1".equals(chkState)) {
            // 未对账，不予处理
            return 1;
        } else if ("3".equals(chkState)) {
            // 对账失败
            vo.setState(3);
            return this.epayFiscMapper.setCheckFail(vo);
        } else {
            // 对账成功，默认按成功处理
            if (chkAcctOrd == null || chkAcctOrd.trim().length() == 0) return -11;
            if (checkDate == null || checkDate.trim().length() != 10) return -11;
            vo.setChkAcctOrd(chkAcctOrd.trim());
            vo.setCheckDate(checkDate.trim());
            vo.setState(2);

            return this.epayFiscMapper.setCheck(vo);
        }
    }


    /**
     * 保存退款流水
     * @param billNum 票号
     * @param backBankAffirm 交易流水
     * @param backTime 交易时间
     * @return 1-成功；0-入库失败；-11-参数错误
     */
    public int setBackPay(String billNum, String backBankAffirm, String backTime, String money) {
        if (billNum == null || billNum.trim().length() == 0) return -11;
        if (backBankAffirm == null || backBankAffirm.trim().length() == 0) return -11;
        if (backTime == null || backTime.trim().length() != 19) return -11;

        EpayFiscVO vo = new EpayFiscVO();
        vo.setBillNum(billNum.trim());
        vo.setBackBankAffirm(backBankAffirm.trim());
        vo.setBackTime(backTime.trim());
        vo.setState(4);

        return this.epayFiscMapper.setBackPay(vo);
    }

    /**
     * 保存划款流水
     * @param billNum 票号
     * @param paymentDate 划款日期
     * @return 1-成功；0-入库失败；-11-参数错误
     */
    public int setPayment(String billNum, String paymentDate) {
        if (billNum == null || billNum.trim().length() == 0) return -11;
        if (paymentDate == null || paymentDate.trim().length() == 0) return -11;

        EpayFiscVO vo = new EpayFiscVO();
        vo.setBillNum(billNum);
        vo.setPaymentDate(paymentDate);
        vo.setState(5);

        return this.epayFiscMapper.setPayment(vo);
    }

    /**
     * 查询余额
     * @param
     */
    public void getBankBalance(HBFSDTO hbfsDto){
        if (CertAndQueue.CACERTID == null) {
            parameterService.selectFselecertandqueue();
        }

        ArrayList<SetRealBankBalanceDTO> setBals = new ArrayList<>();
        //xml解析器
        Serializer serializer = new Persister();
        try{
            //解密数据
            JDCA jdca = new JDCA();
            String message = jdca.decodeEnvelop(hbfsDto.getBody().getMessage(),hbfsDto.getHead().getIsencrypt());
            if(jdca.verifySignMessage(hbfsDto.getBody().getSignmessage(), message, hbfsDto.getHead().getIsencrypt())){
                GetRealBankBalance getBal = new GetRealBankBalance();
                getBal = serializer.read(GetRealBankBalance.class, new StringReader(message));

                if(getBal !=null && getBal.getBlance() !=null && getBal.getBlance().size() >0) {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    String ft = sdf.format(new Date());
                    for(GetRealBankBalanceDTO dto:getBal.getBlance()) {
                        if(dto!=null && dto.getAccountnum() !=null && !dto.getAccountnum().trim().equals("") && dto.getBankid() > 0) {
                            // 调用余额获取
                            String bal = this.getBalance(dto.getAccountnum().trim());
                            if (bal == null) continue;
                            SetRealBankBalanceDTO setDto = new SetRealBankBalanceDTO();
                            setDto.setBankid(dto.getBankid());
                            setDto.setAccountnum(dto.getAccountnum().trim());
                            setDto.setAccountdate(ft);
                            setDto.setFund(bal);
                            setBals.add(setDto);
                            BankBalanceVO bankBalanceVO = new BankBalanceVO();
                            bankBalanceVO.setFund(new BigDecimal(bal));
                            bankBalanceVO.setAccountcode(dto.getAccountnum());
                            bankBalanceVO.setAccountdate(ft);
//                            bankBalanceVO.setBankid(String.valueOf(dto.getBankid()));
                            bankBalanceService.setBankBalance(bankBalanceVO);
                        }
                    }
                }
            }
            jdca=null;
        }catch(Exception e){
            logger.info("获取账户余额失败" + e.toString());
            return;
        }finally{
            serializer = null;
        }

        // 返回报文
        if (setBals.size() == 0) return;
        try {
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            //设置返回信息
            SetRealBankBalance bals = new SetRealBankBalance();
            bals.setBlance(setBals);
            messageService.sendMessage("SETREALBANKBALANCE", messageid, setBals, "2.0");

        }catch(Exception e){
            logger.info("返回账户余额失败" + e.toString());
            return;
        }finally{
            serializer = null;
        }
    }

    /**
     * 从核心获得账户余额
     * @param accountCode 账号
     * @return
     */
    public String getBalance(String accountCode) {

        SocketClientCore socket = new SocketClientCore();
        String content="<?xml version=\"1.0\" encoding=\"GB2312\"?><message><head>"+
                "<channel>ntox</channel>"+
                "<transcode>931002</transcode>"+
                "<transdate>"+ GTimeUtil.getDateTime().substring(0, 8)+"</transdate>"+
                "<transtime>"+GTimeUtil.getDateTime().substring(8, 14)+"</transtime>"+
                "<serialno>"+ UniqId.getInstanceWithLog().getUniqID()+"</serialno>"+
                "<oper></oper>"+
                "</head>"+
                "<body>"+
                "<acctno>"+accountCode+"</acctno>"+
                "<acctname></acctname>"+
                "</body>"+
                "</message>";
        String fund = null;
        try {
            fund = socket.Client(content);
        }catch (Exception e) {
            logger.info(e.toString());
        }

        return fund;
    }

    /**
     * 发送划款
     * @param billNum
     * @return
     */
    public int setBankPayment(String billNum, EpayFiscVO fisc) {
        if (fisc == null) fisc = this.epayFiscMapper.getFisc(billNum);
        if (fisc == null) return 11;
        if (fisc.getState() != 2 && fisc.getState() != 5) return 12;

        if (CertAndQueue.CACERTID == null) {
            parameterService.selectFselecertandqueue();
        }

        try {
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");

            //设置返回信息
            SetBankPaymentDTO dto = new SetBankPaymentDTO();
            dto.setAccountname(fisc.getAccountName());
            dto.setAccountnum(fisc.getAccountCode());
            dto.setBankcheckid(fisc.getTraNo());
            dto.setBillnum(fisc.getBillNum());
            dto.setMoney(fisc.getMoney().toPlainString());
            dto.setPaymentdate(fisc.getPaymentDate());
            ArrayList<SetBankPaymentDTO> bills = new ArrayList<>();
            bills.add(dto);
            SetBankPayment set = new SetBankPayment();
            set.setBills(bills);

            messageService.sendMessage("SETBANKPAYMENT", messageid, set, "2.0");

        }catch(Exception e){
            logger.info("发送划款流水失败" + e.toString());
            return 1;
        }

        return 0;
    }

    /**
     * 发送扣款
     * @param billNum
     * @return
     */
    public int setEPayFisc(String billNum) {
        EpayFiscVO fisc = this.epayFiscMapper.getFisc(billNum);
        if (fisc == null) return 11;
        if (fisc.getState() != 2 && fisc.getState() != 5) return 12;

        if (CertAndQueue.CACERTID == null) {
            parameterService.selectFselecertandqueue();
        }

        try {
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            //设置返回信息
            ResetEPayFiscDTO dto = new ResetEPayFiscDTO();
            dto.setBankid(fisc.getBankid());
            dto.setAccountnum(fisc.getAccountCode());
            dto.setPaybankdt(fisc.getPayBankDt());
            dto.setBillnum(fisc.getBillNum());
            dto.setMoney(fisc.getMoney().toPlainString());
            dto.setBankaffirm(fisc.getBankAffirm());

            messageService.sendMessage("RESETEPAYFISC", messageid, dto, "2.0");

        }catch(Exception e){
            logger.info("补发扣款流水失败" + e.toString());
            return 1;
        }finally{
        }
        return 0;
    }

    /**
     * 按划解国库单据发送
     * @param billNum
     * @return
     */
    public int sendFisc(String billNum, EpayFiscVO fisc) {
        if (fisc == null) fisc = this.epayFiscMapper.getFisc(billNum);
        if (fisc == null) return 11;
        if (fisc.getState() != 2 && fisc.getState() != 5) return 12;

        if (CertAndQueue.CACERTID == null) {
            parameterService.selectFselecertandqueue();
        }
        try {
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            SetBankPayFisc setFisc = new SetBankPayFisc();
            setFisc.setPayid(String.valueOf(fisc.getPayid()));
            setFisc.setBillnum(fisc.getBillNum());
            setFisc.setCantonid(String.valueOf(fisc.getCantonid()));
            setFisc.setPayerbankid(String.valueOf(fisc.getBankid()));
            setFisc.setPayeedepart("");
            setFisc.setPayeefisc("");
            setFisc.setItemid("");
            setFisc.setMoney(fisc.getMoney().toPlainString());
            setFisc.setBankaffirm(fisc.getBankAffirm());
            setFisc.setPaybankdt(fisc.getPayBankDt());
            setFisc.setBankstation(fisc.getBankStation());
            //发送到财政
            messageService.sendMessage("SETBANKPAYFISC", messageid, setFisc, "2.0");
            // 写凭证
            if (nonTaxConfig.IS_Pzk) {
                PzkService.sendPzk("SETBANKPAYFISCPZK", setFisc);
            }
        }catch(Exception e){
            logger.info("发送划款流水失败" + e.toString());
            return 1;
        }finally{
        }

        return 0;
    }

    /**
     * 自动预审前，处理当天电子缴库业务
     * 对于state = 1的，检测当天是否收到对账（存在state>1的记录），如果收到按失败处理，否则按成功处理
     *
     * @param bankid 账户ID，等于0时，全部账户
     * @param dt 日期
     */
    public void dealEpayFisc(int bankid, String dt) {
        // 扣款记录
        List<EpayFiscVO> list = this.epayFiscMapper.listFiscByDate(bankid, dt, null, null);
        // 检测当天是否收到对账（存在state>1的记录），如果收到按失败处理，否则按成功处理
        boolean isChk = false;
        for (EpayFiscVO vo : list) {
            if (vo.getState() > 1) {
                isChk = true;
                break;
            }
        }
        for (EpayFiscVO vo : list) {
            if (vo.getState() == 3 || (vo.getState() == 1 && isChk)) {
                // 对账失败、对账后仍然 = 1的，按失败处理
                // 99支出，入库。预审时有的版本不自动发送财政，这里强制发送
//                this.waitaffirmPayInfoService.saveWaitaffirmPayInfo1(Integer.valueOf(vo.getCantonid()), Integer.valueOf(vo.getBankid()), "", "", 0, 0, "电子缴库，未匹配的支出", vo.getBankAffirm(), vo.getPayBankDt(), vo.getMoney().doubleValue());
//                this.waitaffirmPayInfoService.sendWaitaffirmPayInfo(Integer.valueOf(vo.getCantonid()), Integer.valueOf(vo.getBankid()), "", "", 0, 0, "电子缴库，未匹配的支出", vo.getBankAffirm(), vo.getPayBankDt(), vo.getMoney().doubleValue());
            } else if (vo.getState() == 4) {
                //对比退款时间 是今天的不处理，不是今天的，变成待查
                if (!vo.getBackTime().substring(0, 10).equals(dt)) {
                    // 99支出
//                    this.waitaffirmPayInfoService.saveWaitaffirmPayInfo1(Integer.valueOf(vo.getCantonid()), Integer.valueOf(vo.getBankid()), "", "", 0, 0, "电子缴库，未匹配的支出", vo.getBankAffirm(), vo.getPayBankDt(), vo.getMoney().doubleValue());
//                    this.waitaffirmPayInfoService.sendWaitaffirmPayInfo(Integer.valueOf(vo.getCantonid()), Integer.valueOf(vo.getBankid()), "", "", 0, 0, "电子缴库，未匹配的支出", vo.getBankAffirm(), vo.getPayBankDt(), vo.getMoney().doubleValue());
                }
            } else if (vo.getState() == 2 || vo.getState() == 5 || (vo.getState() == 1 && isChk == false)) {
                // 缴库成功，发送国库单据
                this.sendFisc(vo.getBillNum(), vo);
            }
        }

        // 划款记录
        list = this.epayFiscMapper.listFiscByDate(bankid, null, dt, null);
        for (EpayFiscVO vo : list) {
            if (vo.getState() == 5) {
                // 发送划款
                this.setBankPayment(vo.getBillNum(), vo);
            }
        }

        // 退款记录
        list = this.epayFiscMapper.listFiscByDate(bankid, null, null, dt);
        for (EpayFiscVO vo : list) {
            if (vo.getState() == 4) {
                if (!vo.getPayBankDt().substring(0, 10).equals(dt)) {
                    // 待查收入，入库。预审时自动发送财政，整理不再发送
                    WaitaffirmVO waitaffirmVO = new WaitaffirmVO();
                    waitaffirmVO.setPayer("电子缴库退款");
                    waitaffirmVO.setPayeraccount("");
                    waitaffirmVO.setPayerbank("");
                    waitaffirmVO.setAccountcode(vo.getAccountCode());
                    waitaffirmVO.setBankaffirm(vo.getBackBankAffirm());
                    waitaffirmVO.setPaybankdt(vo.getPayBankDt());
                    waitaffirmVO.setBankstation(vo.getBankStation());
                    waitaffirmVO.setOriginfund(new BigDecimal(vo.getMoney().doubleValue()));
                    waitaffirmVO.setPayway(3);
                    waitaffirmVO.setPostscript("电子缴库，未匹配支出的退回");
                    this.waitaffirmService.setWaitaffirm(waitaffirmVO);

                }
            }
        }

    }

}
